package org.xx.armory.rpc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xx.armory.http.MIMETypes;
import org.xx.armory.service.TempFileObject;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Date;

import static org.apache.commons.io.FilenameUtils.getExtension;
import static org.apache.commons.io.IOUtils.write;
import static org.apache.commons.lang3.StringUtils.left;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;
import static org.xx.armory.commons.JsonUtils.toJson;
import static org.xx.armory.commons.Validators.notBlank;
import static org.xx.armory.commons.Validators.notNull;

/**
 * 包含了所有预定义的生成RPC响应的接口。
 *
 * @author Haart
 */
public final class RpcWriters {
    private static final Charset DEFAULT_TEXT_CHARSET = StandardCharsets.UTF_8;
    private static final Logger LOGGER = LoggerFactory.getLogger(RpcWriters.class);

    private RpcWriters() {
    }

    /**
     * 输出文本内容到RPC响应。
     *
     * @param s
     *         待输出的文本内容。
     * @param textType
     *         文本内容的类型。
     * @param response
     *         RPC响应。
     * @throws IllegalArgumentException
     *         如果参数{@code s}，{@code textType}或{@code response}是{@code null}。如果参数{@code textType}只包含空白字符。
     * @throws ResponseException
     *         如果向RPC响应输出内容时出错。
     */
    private static void writeText(
            RpcResponse response,
            String textType,
            String s
    ) {
        notNull(s, "s");
        notBlank(textType, "textType");
        notNull(response, "response");

        final Date now = new Date();

        if (s.length() > 256) {
            LOGGER.trace("write {} ...", left(s, 256));
        } else {
            LOGGER.trace("write {}", s);
        }

        final Charset charset = DEFAULT_TEXT_CHARSET;
        final byte[] bytes = s.getBytes(charset);

        response.setContentSize(bytes.length);
        response.setContentType(textType, charset);
        response.setDate(now);
        response.ok((out) -> write(bytes, out));
    }

    /**
     * 将对象作为纯文本输出到RPC响应。
     *
     * @param obj
     *         待输出的对象。
     * @param response
     *         RPC响应。
     * @throws IllegalArgumentException
     *         如果参数{@code request}是{@code null}, 或者参数{@code response}是{@code null}。
     * @throws ResponseException
     *         如果向RPC响应输出内容时出错。
     */
    public static void writePlainText(
            RpcResponse response,
            Object obj
    ) {
        notNull(response, "response");

        writeText(response, "text/plain", obj != null ? obj.toString() : "");
    }

    /**
     * 将对象作为JSON文本输出到RPC响应。
     *
     * @param obj
     *         待输出的对象。
     * @param response
     *         RPC响应。
     * @throws IllegalArgumentException
     *         如果参数{@code request}是{@code null}, 或者参数{@code response}是{@code null}。
     * @throws ResponseException
     *         如果向RPC响应输出内容时出错。
     */
    public static void writeJson(
            RpcResponse response,
            Object obj
    ) {
        notNull(response, "response");

        final String jsonStr = obj != null ? trimToEmpty(toJson(obj)) : "null";

        writeText(response, "application/json", jsonStr);
    }

    /**
     * 将临时文件对象输出到RPC响应。
     *
     * @param fo
     *         待输出的临时文件对象。
     * @param response
     *         RPC响应。
     * @throws IllegalArgumentException
     *         如果参数{@code request}是{@code null}, 或者参数{@code response}是{@code null}。
     * @throws ResponseException
     *         如果向RPC响应输出内容时出错。
     */
    public static void writeTempFileObject(
            RpcResponse response,
            TempFileObject fo
    ) {
        notNull(response, "response");

        final Date now = new Date();

        final String mimeType = MIMETypes.EXT_MIME_MAP.get("." + getExtension(fo.getName()).toLowerCase());

        final byte[] bytes = fo.getContent();

        response.setContentSize(fo.getSize());
        response.setContentType(mimeType, null);
        response.setDate(now);
        response.ok((out) -> write(bytes, out));
    }
}
